import {AudioClip, AudioSource, Node,director} from "cc"
import {loadAudio} from "../asset";
import {logger} from "../log";

/**
 * @author : 乔磊磊
 * @ide    : WebStorm
 * @date   : 2025/2/18 星期二 22:02
 * @desc   : 音频管理器
 */
export class AudioMgr {
    // 背景音乐播放组件
    private declare _audioSourceMusic: AudioSource
    // 按钮音效播放组件
    private declare _audioSourceBtn: AudioSource
    // 特效音频播放组件
    private declare _audioSourceEffect: AudioSource
    // 默认的按钮音效
    private _btnAudio: AudioClip = null!
    // 音乐音量
    private _musicVolume: number = 1
    // 音效音量
    private _btnVolume: number = 1
    // 音效音量
    private _effectVolume: number = 1

    // 单例模式
    private static _instance: AudioMgr
    public static getInstance() {
        if (AudioMgr._instance) return AudioMgr._instance
        AudioMgr._instance = new AudioMgr()
        return AudioMgr._instance
    }

    private constructor() {
    }

    /**
     * 设置默认的按钮点击音效
     * @param {AudioClip} audio
     */
    public setBtnAudioDefault(audio: AudioClip) {
        this._btnAudio = audio
    }

    /**
     * 设置音乐音量
     */
    public setMusicVolume(musicVolume: number) {
        this._musicVolume = musicVolume
        this._audioSourceMusic.volume = musicVolume
    }

    /**
     * 设置按钮音效音量
     */
    public setBtnVolume(btnVolume: number) {
        this._btnVolume = btnVolume
        this._audioSourceBtn.volume = btnVolume
    }

    /**
     * 设置音效音量
     */
    public setEffectVolume(effectVolume: number) {
        this._effectVolume = effectVolume
        this._audioSourceEffect.volume = effectVolume
    }

    /**
     * 播放按钮音效
     * @param soundPath
     */
    public async playBtnAudio(soundPath: AudioClip | string) {
        if (soundPath instanceof AudioClip) {
            this._audioSourceBtn.playOneShot(soundPath, this._btnVolume);
        } else if (soundPath.trim() !== '') {
            try {
                const sound = await loadAudio(soundPath);
                this._audioSourceBtn.playOneShot(sound, this._btnVolume);
            } catch (error) {
                logger.error(`Failed to load audio: ${soundPath}`, error);
            }
        } else {
            logger.error("Invalid sound path type or format.");
        }
    }

    /**
     * 播放长音频，比如 背景音乐
     * @param soundPath clip or url for the sound
     */
    public async playMusic(soundPath: AudioClip | string) {
        if (this._audioSourceMusic.playing) {
            return
        }
        this._audioSourceMusic.volume = this._musicVolume;
        if (soundPath instanceof AudioClip) {
            this._audioSourceMusic.clip = soundPath;
            this._audioSourceMusic.play();
        } else if (soundPath.trim() !== '') {
            try {
                this._audioSourceMusic.clip = await loadAudio(soundPath);
                this._audioSourceMusic.play();
            } catch (error) {
                logger.error(`Failed to load audio: ${soundPath}`, error);
            }
        } else {
            logger.error("Invalid sound path type or format.");
        }
    }

    /**
     * 播放短音频,比如 打击音效，爆炸音效等
     * @param soundPath clip or url for the audio
     */
    public async playOneShot(soundPath: AudioClip | string) {
        if (soundPath instanceof AudioClip) {
            this._audioSourceEffect.playOneShot(soundPath, this._effectVolume);
        } else if (soundPath.trim() !== '') {
            try {
                const sound = await loadAudio(soundPath);
                this._audioSourceEffect.playOneShot(sound, this._effectVolume);
            } catch (error) {
                logger.error(`Failed to load audio: ${soundPath}`, error);
            }
        } else {
            logger.error("Invalid sound path type or format.");
        }
    }

    public pauseMusic() {
        this._audioSourceMusic.pause();
    }

    public stopMusic() {
        this._audioSourceMusic.stop();
    }

    public init(node: Node) {
        // 添加 AudioSource 组件，用于播放音频。
        this._audioSourceMusic = node.addComponent(AudioSource)
        this._audioSourceMusic.loop = true
        this._audioSourceMusic.playOnAwake = false

        this._audioSourceBtn = node.addComponent(AudioSource)
        this._audioSourceBtn.playOnAwake = false

        this._audioSourceEffect = node.addComponent(AudioSource)
        this._audioSourceEffect.playOnAwake = false
    }
}

let audioMgr: AudioMgr

export function getAudionMgr() {
    if (audioMgr) return audioMgr
    audioMgr =  AudioMgr.getInstance()
    let gameNode = new Node()
    gameNode.name = "__audio__"
    director.getScene()?.getChildByName(gameNode.name)?.destroy()
    director.getScene()?.addChild(gameNode)
    director.addPersistRootNode(gameNode)
    audioMgr.init(gameNode)
    return audioMgr
}
